﻿namespace MicroCloud.Utils
{
    #region "Hash算法帮助类"
    /// <summary>
    /// Hash算法帮助类
    /// </summary>
    public static class HashHelper
    {
        #region "方法"
        #region "获取字符串的MD5哈希值，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 获取字符串的MD5哈希值，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string GetMD5(string value, Encoding encoding = null)
        {
            value = value.ReplaceNull();
            encoding ??= Encoding.UTF8;
            byte[] bytes = encoding.GetBytes(value);
            return GetMD5(bytes);
        }
        #endregion
        #region "获取字节数组的MD5哈希值"
        /// <summary>
        /// 获取字节数组的MD5哈希值
        /// </summary>
        /// <param name="bytes">字节数组</param>
        /// <returns></returns>
        public static string GetMD5(byte[] bytes)
        {
            if (bytes?.Length <= 0)
            {
                return string.Empty;
            }
            StringBuilder sb = new();
            //MD5 hash = MD5.Create();
            //bytes = hash.ComputeHash(bytes);
            bytes = MD5.HashData(bytes);
            foreach (byte b in bytes)
            {
                sb.AppendFormat("{0:x2}", b);
            }
            return sb.ToString();
        }
        #endregion
        #region "获取字符串的SHA1哈希值，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 获取字符串的SHA1哈希值，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string GetSHA1(string value, Encoding encoding = null)
        {
            value.CheckNotNullOrEmpty(nameof(value));

            StringBuilder sb = new();
            SHA1 hash = SHA1.Create();
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            byte[] bytes = hash.ComputeHash(encoding.GetBytes(value));
            foreach (byte b in bytes)
            {
                sb.AppendFormat("{0:x2}", b);
            }
            return sb.ToString();
        }
        #endregion
        #region "获取字符串的SHA256哈希值，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 获取字符串的SHA256哈希值，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string GetSHA256(string value, Encoding encoding = null)
        {
            value.CheckNotNullOrEmpty(nameof(value));

            StringBuilder sb = new();
            SHA256 hash = SHA256.Create();
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            byte[] bytes = hash.ComputeHash(encoding.GetBytes(value));
            foreach (byte b in bytes)
            {
                sb.AppendFormat("{0:x2}", b);
            }
            return sb.ToString();
        }
        #endregion
        #region "获取字符串的SHA512哈希值，默认编码为<see cref="Encoding.UTF8"/>"
        /// <summary>
        /// 获取字符串的SHA512哈希值，默认编码为<see cref="Encoding.UTF8"/>
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="encoding">Encoding编码</param>
        /// <returns></returns>
        public static string GetSHA512(string value, Encoding encoding = null)
        {
            value.CheckNotNullOrEmpty(nameof(value));

            StringBuilder sb = new();
            SHA512 hash = SHA512.Create();
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            byte[] bytes = hash.ComputeHash(encoding.GetBytes(value));
            foreach (byte b in bytes)
            {
                sb.AppendFormat("{0:x2}", b);
            }
            return sb.ToString();
        }
        #endregion

        #region "计算文件的MD5值"
        /// <summary>
        /// 计算文件的MD5值
        /// </summary>
        /// <param name="FilePath">要计算MD5值的文件名和路径</param>
        /// <returns>MD5值16进制字符串</returns>
        public static string GetFileMD5(string FilePath)
        {
            return HashFile(FilePath, AlgType.MD5);
        }
        #endregion
        #region "计算文件的SHA1值"
        /// <summary>
        /// 计算文件的SHA1值
        /// </summary>
        /// <param name="FilePath">要计算SHA1值的文件名和路径</param>
        /// <returns>SHA1值16进制字符串</returns>
        public static string GetFileSHA1(string FilePath)
        {
            return HashFile(FilePath, AlgType.SHA1);
        }
        #endregion
        #region "计算文件的哈希值"
        /// <summary>
        /// 计算文件的哈希值
        /// </summary>
        /// <param name="fileName">要计算哈希值的文件名和路径</param>
        /// <param name="algType">算法:sha1,md5</param>
        /// <returns>哈希值16进制字符串</returns>
        public static string HashFile(string fileName, AlgType algType)
        {
            if (!File.Exists(fileName))
            {
                return string.Empty;
            }
            FileStream fs = new(fileName, FileMode.Open, FileAccess.Read);
            byte[] hashBytes = HashData(fs, algType);
            fs.Close();
            return ByteArrayToHexString(hashBytes);
        }
        #endregion

        #region "计算Stream的MD5值"
        /// <summary>
        /// 计算Stream的MD5值
        /// </summary>
        /// <param name="stream">要计算哈希值的Stream</param>
        /// <returns>MD5值16进制字符串</returns>
        public static string GetStreamMD5(Stream stream)
        {
            return HashStream(stream, AlgType.MD5);
        }
        #endregion
        #region "计算Stream的SHA1值"
        /// <summary>
        /// 计算Stream的SHA1值
        /// </summary>
        /// <param name="stream">要计算哈希值的Stream</param>
        /// <returns>SHA1值16进制字符串</returns>
        public static string GetStreamSHA1(Stream stream)
        {
            return HashStream(stream, AlgType.SHA1);
        }
        #endregion
        #region "计算Stream的哈希值"
        /// <summary>
        /// 计算Stream的哈希值
        /// </summary>
        /// <param name="stream">要计算哈希值的Stream</param>
        /// <param name="algType">算法:sha1,md5</param>
        /// <returns>哈希值值16进制字符串</returns>
        public static string HashStream(Stream stream, AlgType algType)
        {
            byte[] hashBytes = HashData(stream, algType);

            //stream.Position = 0;
            stream.Seek(0, SeekOrigin.Begin);   //设置当前流的位置为流的开始

            return ByteArrayToHexString(hashBytes);
        }
        #endregion

        #region "计算Stream的哈希值字节数组"
        /// <summary>
        /// 计算Stream的哈希值字节数组
        /// </summary>
        /// <param name="stream">要计算哈希值的Stream</param>
        /// <param name="algType">算法:sha1,md5</param>
        /// <returns>哈希值字节数组</returns>
        public static byte[] HashData(Stream stream, AlgType algType)
        {
            HashAlgorithm algorithm = null;
            switch (algType)
            {
                case AlgType.MD5:
                    algorithm = MD5.Create();
                    break;
                case AlgType.SHA1:
                    algorithm = SHA1.Create();
                    break;
            }
            return algorithm.ComputeHash(stream);
        }
        #endregion

        #region "哈希值字节数组转换为16进制表示的字符串"
        /// <summary>
        /// 哈希值字节数组转换为16进制表示的字符串
        /// </summary>
        public static string ByteArrayToHexString(byte[] buf)
        {
            return BitConverter.ToString(buf).Replace("-", "");
        }
        #endregion

        #endregion

    }
    #endregion

}
